package org.haredot.listener;

import com.rabbitmq.client.Channel;
import org.haredot.constant.RabbitConst;
import org.haredot.entity.LoginLog;
import org.haredot.entity.ServiceLog;
import org.haredot.mapper.LoggerMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class QueueListener {

    @Value("${spring.rabbitmq.listener.simple.retry.max-attempts}")
    private int retryMaxCount  ;

    private AtomicInteger retryCount = new AtomicInteger(0);

    private AtomicInteger retryCount2 = new AtomicInteger(0);

    private final Logger logger = LoggerFactory.getLogger(QueueListener.class);

    @Resource
    private LoggerMapper loggerMapper ;

    @RabbitListener(queues= RabbitConst.SERVICE_LOG_QUEUE)
    public void writeMessageToServiceLog(Channel channel ,
                                       @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
                                       ServiceLog serviceLog) throws IOException {
        // 打印 消息的内容
        try {
            // 负责 将数据写入到数据库
            loggerMapper.saveServiceLog(serviceLog) ;
            // 确认消息
            channel.basicAck(deliveryTag , false);
            retryCount2.set(0);
        } catch (Exception e) {
           if ( retryCount.incrementAndGet() >= retryMaxCount ) {
               retryCount.set(0); // 重置为 0
               // 负面确认
               channel.basicNack(deliveryTag, false, false);
               // 将错误的消息 记录到 数据库中，以备后续的人工补偿
               // 结合 定时任务 将 错误的消息 在 某段时间 后 继续入队，再次消费
           }else{
               throw e ;
           }
        }
    }


    @RabbitListener(queues= RabbitConst.LOGIN_LOG_QUEUE)
    public void writeMessageToLoginLog(Channel channel ,
                                       @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
                                       LoginLog log) throws IOException {
        // 打印 消息的内容
        try {
            // 负责 将数据写入到数据库
            loggerMapper.saveLoginLog(log) ;

            // 确认消息
            channel.basicAck(deliveryTag , false);
            retryCount2.set(0);
        } catch (Exception e) {
            if ( retryCount2.incrementAndGet() >= retryMaxCount ) {
                retryCount2.set(0);
                // 负面确认
                channel.basicNack(deliveryTag, false, false);
                // 将错误的消息 记录到 数据库中，以备后续的人工补偿
                // 结合 定时任务 将 错误的消息 在 某段时间 后 继续入队，再次消费
            }else{
                throw e ;
            }
        }
    }

    @RabbitListener(queues= RabbitConst.LOGS_ALL_QUEUE, ackMode = "AUTO")
    public void printMessageLog(Channel channel ,
                                @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
                                Message message) throws IOException {
        // 打印 消息的内容
        byte[] payload = message.getBody();
        logger.info(new String(payload, StandardCharsets.UTF_8));
    }
}
